package ClientManager;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 客户端管理程序
 */

public class ClientManager {

    public CacheManager cacheManager;
    public MasterSocketManager masterSocketManager;
    public RegionSocketManager regionSocketManager;

    public ClientManager() throws IOException {
        this.cacheManager = new CacheManager();
        this.masterSocketManager = new MasterSocketManager(this);
        this.regionSocketManager = new RegionSocketManager();
    }

    // 初步解析sql，获取操作类型以及要操作的表，从缓存里找
    public void run()
            throws IOException, InterruptedException {
        System.out.println("Client start!");
        Scanner input = new Scanner(System.in);
        String line = "";
        while (true) {
            StringBuilder sql = new StringBuilder();
            //sql读取
            System.out.println("Enter the sql:");
            while (line.isEmpty() || line.charAt(line.length() - 1) != ';') {
                line = input.nextLine();
                if (line.isEmpty()) {
                    continue;
                }
                sql.append(line);
                sql.append(' ');
            }
            line = "";
            System.out.println(sql);
            String s = sql.substring(0,sql.length()-2);
            if (s.trim().equals("quit;")) {
                this.masterSocketManager.closeMasterSocket();
                if (this.regionSocketManager.socket != null) {
                    this.regionSocketManager.closeRegionSocket();
                }
                break;
            }

            // 获得目标表名和索引名
            String command = s;
            Map<String, String> target = this.sqlParser(command);
            if (target.containsKey("error")) {
                System.out.println("Invalid SQL!");
                this.masterSocketManager.sendMaster(5,"");
                continue;
            }

            String table = target.get("name");
            String mainCache = null;
            System.out.println("table name: " + table);
            if (target.get("kind").equals("create")) {
                this.masterSocketManager.processCreate(command, table);
            } else if(target.get("kind").equals("select")){//select可从三个map进行操作
                //找缓存，顺序为副1，副2，主
                String cache = null;
                cache = cacheManager.getSubCache1(table);
                this.connectToRegion(cache,command,1,table);
            }else if(target.get("kind").equals("show")) {//show tables
                this.masterSocketManager.sendMaster(3,"");
            }else{
                //直接连main cache
                this.connectToRegion(cacheManager.getMainCache(table),command,3,table);
                    //操作需要缓存
//                    mainCache = cacheManager.getMainCache(table);
//                    if (mainCache == null) {
//                        System.out.println("There is no cache, request from master...");
//                        // cache里面没有找到表所对应的端口号，去masterSocket里面查询
//                         this.masterSocketManager.process(command, table);
//                         //测试用
//
//                    } else {
//                        //直接在RegionSocketManager中进行连接
//                        System.out.println("There exists cache, ip is " + mainCache);
//                         this.connectToRegion(mainCache, command,3,table);
//                    }
//                    if (fcache == null) {
//
//                        this.masterSocketManager.process(command,target.get("kind"), table);
//                    } else {
//                        // 如果查到了端口号就直接在RegionSocketManager中进行连接
//                        this.connectToRegion(fcache, command);
//                        if(!target.get("kind").equals("select")){
//                            //非select 再连副
//                            scache = cacheManager.getSubCache1(table);
//                            if(!scache.equals(fcache)){
//                                this.connectToRegion(scache, command);
//                            }
//                        }
//                    }
//                }
            }
        }
    }

    //连接region的端口号固定为6666，order为当前缓存的序号，当前没有就找下一个缓存
    public void connectToRegion(String ip, String sql,int order,String table) throws IOException, InterruptedException {

        Map<String, String> target = this.sqlParser(sql);
       if(ip != null && this.regionSocketManager.connectRegionServer(ip)){
           System.out.println("There exists cache, ip: "+ip);
            Thread.sleep(100);
            if(target.get("kind").equals("select")){
                this.regionSocketManager.sendToRegion(sql,6);
            }else{//需要加上两个从副本的ip
                StringBuilder info = new StringBuilder(table);
                info.append(",").append(sql).append(",");
                info.append((cacheManager.getSubCache1(table) != null) ? cacheManager.getSubCache1(table) : "").append(",");
                info.append((cacheManager.getSubCache2(table)) != null ? cacheManager.getSubCache2(table) : "");
                this.regionSocketManager.sendToRegion(info.toString(), 12);
            }
            if (target.get("kind").equals("drop")){
                //delete the corresponding cache
                this.cacheManager.delCache(target.get("name"));
            }
        } else{
           System.out.println("no cache, order="+order);
            //region 挂了，继续找下一个缓存
            if(order == 1){//下一个找副2
                connectToRegion(cacheManager.getSubCache2(table),sql,2,table);
            }else if(order == 2){//下一个找主
                connectToRegion(cacheManager.getMainCache(table),sql,3,table);
            }else{//向master请求
                System.out.println("There is no cache, request from master...");
                if(target.get("kind").equals("create")){
                    this.masterSocketManager.processCreate(sql, target.get("name"));
                } else{
                    this.masterSocketManager.process(sql, target.get("name"));
                }
                Thread.sleep(1000);//等待master传回消息
                //向region发消息
                if(!cacheManager.hasCache(table)){
                    return;
                }
                if(target.get("kind").equals("select")){
                    connectToRegion(cacheManager.getSubCache1(table),sql,1,table);
                }else{
                    connectToRegion(cacheManager.getMainCache(table),sql,3,table);
                }
            }
        }
    }
    // parse the sql
    private Map<String, String> sqlParser(String sql) {
        // 粗略地解析需要操作的table和index的名字
        Map<String, String> result = new HashMap<>();
        // 空格替换
        sql = sql.replaceAll("\\s+", " " );
        String[] words = sql.split(" ");
        // SQL语句的种类
        result.put("kind", words[0]);
        if (words[0].equals("create")) {
            // 对应create table xxx和create index xxx
            // 此时创建新表，不需要cache
            result.put("cache", "false");
            result.put("name", words[2]);
        } else if (words[0].equals("drop") || words[0].equals("insert") || words[0].equals("delete")) {
            // 这三种都是将table和index放在第三个位置的，可以直接取出
            String name = words[2].replace("(", "")
                    .replace(")", "").replace(";", "");
            result.put("name", name);
        } else if (words[0].equals("select")) {
            // select语句的表名放在from后面
            for (int i = 0; i < words.length; i ++) {
                if (words[i].equals("from") && i != words.length - 1) {
                    result.put("name", words[i + 1]);
                    break;
                }
            }
        } else if(words[0].equals("show")){
            result.put("show", words[0]);
            return result;
        }else if(words[0].equals("update")){
            result.put("name",words[1]);
        }
        // 如果没有发现表名就说明出现错误
        if (!result.containsKey("name")) {
            result.put("error", "true");
        }
        return result;
    }

}
